{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## How convert MegEngine model file to Tengine model file\n",
    "\n",
    "这里补充 Tengine 介绍和 MegEngine 介绍。\n",
    "本节教程说明了如何将 MegEngine model 转换为 Tengine model 的过程和注意事项。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### load a MegEngine model form MegEngine.Hub\n",
    "MegEngine ModHub 包含了采用MegEngine实现的各种主流深度学习模型，提供了各种经典的图像分类、目标检测、图像分割以及自然语言模型的官方实现，每个模型同时提供了模型定义、推理以及训练的代码。\n",
    "以经典的 ResNet 网络结构为例，MegEngine ModHub 提供了 ImageNet 数据集上的预训练模型和完整训练及测试代码。下面以 resnet18 为例，说明了如何将 MegEngine resnet18 模型转换为 Tengine resnet18 模型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\u001b[32m04 16:29:21 \u001b[0mload_serialized_obj_from_url: download to or using cached /home/i/.cache/megengine/serialized/009607_resnet18_naiveaug_70312_78a63ca6.pkl\n"
     ]
    }
   ],
   "source": [
    "import megengine.hub\n",
    "\n",
    "# 只加载网络结构\n",
    "#resnet18 = megengine.hub.load(\"megengine/models\", \"resnet18\")\n",
    "\n",
    "# 加载网络结构和预训练权重\n",
    "resnet18 = megengine.hub.load(\"megengine/models\", \"resnet18\", pretrained=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于 MegEngine ModHub 下载的模型和训练得到的原始 MegEngine 模型，需要注意的是模型并未完成*序列化*，需要先将模型序列化后才可进行转换。\n",
    "详见：https://megengine.org.cn/doc/latest/advanced/deployment.html#id2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from megengine.jit import trace\n",
    "import megengine.functional as F\n",
    "\n",
    "# 使用 trace 装饰该函数，详情见 MegEngine 文档“动态图与静态图”、“静态图的两种模式”章节\n",
    "# pred_fun 经过装饰之后已经变成了 trace 类的一个实例，而不仅仅是一个函数\n",
    "@trace(symbolic=True)\n",
    "def pred_fun(data, *, net):\n",
    "    net.eval()\n",
    "    pred = net(data)\n",
    "    # if model has softmax\n",
    "    pred_normalized = F.softmax(pred)\n",
    "    return pred_normalized"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过 numpy 声明随机产生一个 (1, 3, 224, 224) 大小的浮点进行输入填充，以便 MegEngine 进行序列化。\n",
    "需要注意的是，该大小需要和最后部署场景中的大小有关，具体取决于网络的结构限制，比如 FC Layer。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "data = np.random.random((1, 3, 224, 224)).astype(np.float32)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "pred_fun.trace(data, net=resnet18)\n",
    "pred_fun.dump('new_model.pkl')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "将被 trace 装饰的函数（这里的 pred_fun ）视为计算图的全部流程，计算图的输入严格等于 pred_fun 的位置参数（positional arguments，即参数列表中星号 * 前的部分，这里的 data 变量），计算图的输出严格等于函数的返回值（这里的 pred_normalized ）。\n",
    "此步骤详细说明还可参考 MegEngine 的 [deployment](https://megengine.org.cn/doc/latest/advanced/deployment.html#deployment) 文档。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最后输出的 new_model.pkl 就是序列化后的 MegEngine 模型了。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通过下面的命令，可以将 MegEngine 模型转换为 Tengine tmfile 格式的模型：\n",
    "``` bash\n",
    "convert_tool -f megengine -m new_model.pkl -o res18_megengine.tmfile\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}